package gu.sql2java.json;

import java.io.IOException;
import java.util.BitSet;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonTokenId;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.PrimitiveArrayDeserializers;
import com.fasterxml.jackson.databind.ser.std.StdArraySerializers;

/**
 * {@link BitSet} 的JACKSON序列化和反序列化实现
 * @author guyadong
 * @since 3.30.1
 */
public class BitSetJacksonCodec {
	public static final Deserializer DESERIALIZER = new Deserializer();
	public static final Serializer SERIALIZER = new Serializer();
	/**
	 * 将索引大于等于length的位清0
	 * @param bitSet
	 * @param length
	 * @return 输入参数为{@code null}返回原值，否则返回清0后的新对象
	 */
	private static BitSet leftSet(BitSet bitSet,Integer length) {
		if(null != bitSet && null != length) {
			if(length < bitSet.length()) {
				return bitSet.get(0,length);
			}
		}
		return bitSet;
	}
	/**
	 * {@link BitSet}反序列化实现
	 */
	public static class Deserializer extends JsonDeserializer<BitSet> {
		private final JsonDeserializer<?> longArrayDeserializer = PrimitiveArrayDeserializers.forType(long.class);
		/** 最大bit位限制,大于等于此值的索引位值在反序列化时被忽略 */
		private Integer bitLimit;
		public Deserializer() {
		}
		public Deserializer(Integer bitLimit) {
			if(null != bitLimit && bitLimit < 0) {
				throw new IllegalArgumentException("bitLimit < 0: " + bitLimit);
			}
			this.bitLimit = bitLimit;
		}
		@Override
		public BitSet deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
	        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
	        switch(jp.currentTokenId()) {
	        case JsonTokenId.ID_NULL:
	        	jp.nextToken();
	        	return null;
	        case  JsonTokenId.ID_START_ARRAY:{
	        	long[] longs = (long[]) longArrayDeserializer.deserialize(jp, ctxt);
	        	return leftSet(BitSet.valueOf(longs),bitLimit);
	        }
	        case JsonTokenId.ID_STRING:{
	        	/** 递归 */
	        	String text = jp.getText();
	        	jp.nextToken();
	        	return mapper.readValue(text, BitSet.class);
	        }
	        default:{
	        	BitSet bitSet = leftSet(BitSet.valueOf(new long[] {jp.getNumberValue().longValue()}),bitLimit);
	        	jp.nextToken();
	        	return bitSet;
	        }
	        }
		}
		public static class I8 extends Deserializer{
			public I8() {
				super(Byte.SIZE);
			}		
		}
		public static class I16 extends Deserializer{
			public I16() {
				super(Short.SIZE);
			}		
		}
		public static class I32 extends Deserializer{
			public I32() {
				super(Integer.SIZE);
			}		
		}
		public static class I64 extends Deserializer{
			public I64() {
				super(Long.SIZE);
			}		
		}
	}
	/**
	 * {@link BitSet}序列化实现
	 */
	public static class Serializer extends JsonSerializer<BitSet> {
		@SuppressWarnings({ "rawtypes" })
		private final JsonSerializer longArraySerializer = StdArraySerializers.findStandardImpl(long[].class);
		/** 最大bit位限制,大于等于此值的索引位值在序列化时被忽略 */
		private Integer bitLimit;
		public Serializer() {
		}
		public Serializer(Integer bitLimit) {
			if(null != bitLimit && bitLimit < 0) {
				throw new IllegalArgumentException("bitLimit < 0: " + bitLimit);
			}
			this.bitLimit = bitLimit;
		}
		@SuppressWarnings("unchecked")
		@Override
		public void serialize(BitSet value, JsonGenerator gen, SerializerProvider serializers)
				throws IOException, JsonProcessingException {
			if(null == value) {
				gen.writeNull();
			}else {
				if(bitLimit != null) {
					value = leftSet(value,bitLimit);
					if(bitLimit <= Long.SIZE) {
						gen.writeNumber(value.toLongArray()[0]);
						return;
					}
				}
				longArraySerializer.serialize(leftSet(value,bitLimit).toLongArray(), gen, serializers);
			}
		}
		public static class I8 extends Serializer{
			public I8() {
				super(Byte.SIZE);
			}
		}
		public static class I16 extends Serializer{
			public I16() {
				super(Short.SIZE);
			}
		}
		public static class I32 extends Serializer{
			public I32() {
				super(Integer.SIZE);
			}
		}
		public static class I64 extends Serializer{
			public I64() {
				super(Long.SIZE);
			}
		}
	}
}
